# -*- coding: utf-8 -*-
# created on 2017/2/17

from mathsolver.functions.base import *
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaOptimize
from mathsolver.functions.process import ProcessExpression
from sympy import *


class SimpleOptimize(BaseFunction):
    def solver(self, *args):
        poly_v, text = args
        if "最大" in text:
            output = BaseOptimize(poly_v.value, "Maximize")
        elif "最小" in text:
            output = BaseOptimize(poly_v.value, "Minimize")
        else:
            raise Exception("to do")
        self.output.append(output)
        return self


class Optimize(BaseFunction):
    def solver(self, *args):
        poly_v, text = args
        if "最大" in text:
            output = BaseOptimize(poly_v.value, "Maximize")
            flag = "最大值"
        elif "最小" in text:
            output = BaseOptimize(poly_v.value, "Minimize")
            flag = "最小值"
        else:
            raise ValueError()

        if poly_v.sympify().is_Symbol:
            value = self.search(poly_v.sympify())
        else:
            value = poly_v.sympify()

        if isinstance(value, Set):
            if flag == "最大值":
                v = value.sup
            elif flag == "最小值":
                v = value.inf
            else:
                raise Exception("to do")
            self.steps.append(["", "%s为%s" % (flag, new_latex(v))])
            self.output.append(BasePoly(v))
            return self

        equations = self.known["equations"]
        unequations = self.known["inequations"]

        if equations or unequations:
            output.cond = BaseIneqs(equations + unequations)

        output = MathematicaOptimize().solver(output, None).output
        if isinstance(output[0], BaseNumber):
            number, cond = output[:2]
            self.steps.append(["当%s时" % cond.printing(), "%s为%s" % (flag, new_latex(number.sympify().simplify()))])
            self.output.append(output[0])
        else:
            ans = output[0]
            for number, cond in ans:
                cond = BaseIneqs(cond)
                self.steps.append(["当%s时" % cond.printing(), "%s为%s" % (flag, new_latex(sympify(number)))])
            self.output.append(BaseNumbers([number for number, _ in ans]))

        self.label.add("最值问题")
        return self


class PolyRegion(BaseFunction):
    @staticmethod
    def get_region(exprr, cond):
        max_v = MathematicaOptimize().solver(BaseOptimize(exprr, "Maximize", cond), None).output

        min_v = MathematicaOptimize().solver(BaseOptimize(exprr, "Minimize", cond), None).output

        max_open = False
        min_open = False

        if not max_v[-1]:
            max_open = True
        if not min_v[-1]:
            min_open = True

        max_value = max_v[0].sympify()
        min_value = min_v[0].sympify()
        return Interval(min_value, max_value, min_open, max_open)

    def solver(self, *args):
        poly_v = args[0]
        if self.search(poly_v.sympify()):
            ans = self.search_multiple([poly_v.sympify()])
            res = []
            if isinstance(ans, PieceWise):
                for tmv, value in ans.pieces:
                    if tmv.free_symbols:
                        res.append(self.get_region(tmv, value))
                    elif isinstance(tmv, Set):
                        res.append(tmv)
                    else:
                        res.append(FiniteSet(tmv))

                res = Union(*res)
                self.steps.append(["取值范围是：", new_latex(res)])
                self.output.append(BaseValue(res))
                return self

            ans = self.search(poly_v.sympify())
            if isinstance(ans, FiniteSet):
                res = Union(*[a if isinstance(a, Set) else FiniteSet(a) for a in ans])
            else:
                res = ans

            if not res.free_symbols:
                self.steps.append(["取值范围是：", new_latex(res)])
                self.output.append(BaseValue(res))
                return self
            elif isinstance(res, FiniteSet):
                pass

        equations = self.known["equations"]
        unequations = self.known["inequations"]
        cond = []
        if equations or unequations:
            cond.append(BaseIneqs(equations + unequations))

        syms = list(poly_v.free_symbols())
        if len(syms) == 1 and self.search(syms[0]):
            cond.append({syms[0]: self.search(syms[0])})

        res = self.get_region(poly_v.value, cond)  # Interval(min_value, max_value, min_open, max_open)
        self.steps.append(["取值范围是：", new_latex(res)])
        self.output.append(BaseValue(res))
        self.label.add("利用函数图像转化参数关系")
        return self


class IsDengCha(BaseFunction):
    def solver(self, *args):
        values = args[0].sympify()
        if len(values) == 3:
            eq = [values[0] + values[2], 2 * values[1]]
            self.output.append(BaseEq(eq))
        self.label.add("等差数列的性质")
        return self


class IsDengBi(BaseFunction):
    def solver(self, *args):
        values = args[0].sympify()
        if len(values) == 3:
            eq = [values[0] * values[2], values[1] ** 2]
            self.output.append(BaseEq(eq))
            self.label.add("等比数列的性质")
        return self


class BiZhi(BaseFunction):
    def solver(self, *args):
        value = args[0].sympify() / args[1].sympify()
        self.output.append(BasePoly(value))
        return self


class ProcessVectorEq(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].value
        assert "vec" in str(f1) or "vec" in str(f2)
        f1 = ProcessExpression(known=self.known).solver(BaseValue(f1)).output[0].value if "vec" in str(f1) or sympify(
            f1).free_symbols else f1
        f2 = ProcessExpression(known=self.known).solver(BaseValue(f2)).output[0].value if "vec" in str(f2) or sympify(
            f2).free_symbols else f2
        if isinstance(f1, list) and isinstance(f2, list):
            self.output.append(BaseEqs([[f1[0], f2[0]], [f1[1], f2[1]]]))
        elif isinstance(f1, str) and isinstance(f2, str):
            self.output.append(BaseEq([f1, f2]))
        else:
            raise ValueError()
        return self


class ProcessGeoEq(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].value
        poly1 = ProcessExpression(known=self.known).solver(BasePoly(f1)).output[0].sympify()
        poly2 = ProcessExpression(known=self.known).solver(BasePoly(f2)).output[0].sympify()

        if poly1.func == acos:
            poly1 = poly1.args[0]
            obj = BaseEq([poly1, cos(poly2)])
        else:
            obj = BaseEq([poly1, poly2])

        self.output.append(obj)
        self.steps.append([latex_symbol["because"] + args[0].printing(), ""])
        self.steps.append([obj.printing(), ""])

        return self


class VectorJiaJiao(BaseFunction):
    def solver(self, *args):
        f1, f2 = ProcessExpression(known=self.known).solver(args[0]).output[0].sympify()
        f3, f4 = ProcessExpression(known=self.known).solver(args[1]).output[0].sympify()
        ans = acos((f1 * f3 + f2 * f4) / (sqrt(f1 ** 2 + f2 ** 2) * sqrt(f3 ** 2) + f4 ** 2))
        self.output.append(BasePoly(ans))
        self.label.add("两向量夹角")
        return self


class ThreeEqArea(BaseFunction):
    def solver(self, *args):
        a1, b1, c1 = args[0].value
        a2, b2, c2 = args[1].value
        a3, b3, c3 = args[2].value
        u = solve([a1 * x + b1 * y + c1, a2 * x + b2 * y + c2], [x, y])
        u1 = u[x]
        u2 = u[y]
        v = solve([a1 * x + b1 * y + c1, a3 * x + b3 * y + c3], [x, y])
        v1 = v[x]
        v2 = v[y]
        w = solve([a2 * x + b2 * y + c2, a3 * x + b3 * y + c3], [x, y])
        w1 = w[x]
        w2 = w[y]
        da = Matrix([[u1, u2, 1], [v1, v2, 1], [w1, w2, 1]])
        s = det(da) / 2
        self.output.append(BasePoly(Abs(s)))
        self.label.add("三条直线构成区域面积")
        self.steps.append(["三条直线构成区域面积为 %s" % (new_latex(Abs(s))), ""])
        return self


class VariableIsPoint(BaseFunction):
    def solver(self, *args):
        v = args[0].sympify()
        p = args[1].sympify()
        self.output.append(BaseEq([v, p[0]]))
        return self


class AnyIsInter(BaseFunction):
    def solver(self, *args):
        any_, inter = args[:2]
        if isinstance(inter.interval, Interval):
            args = inter.interval.args
            ineq = [args[0], "<" if args[2] else "<=", any_.sympify(), "<" if args[3] else "<=", args[1]]
            self.output.append(BaseIneqs(ineq))
        else:
            obj = BaseBelong([])
            obj.var = any_.sympify()
            obj.interval = inter.interval
            self.output.append(obj)
        return self


class ZhengQie(BaseFunction):
    def solver(self, *args):
        v = args[0].sympify()
        self.output.append(BasePoly(tan(v)))
        return self


class YuXian(BaseFunction):
    def solver(self, *args):
        v = args[0].sympify()
        self.output.append(BasePoly(cos(v)))
        return self


class ChengJi(BaseFunction):
    def solver(self, *args):
        v = args[0].sympify() * args[1].sympify()
        self.output.append(BasePoly(v))
        return self


if __name__ == '__main__':
    pass
